﻿
Imports System.Xml
Imports System.Text

Public Class TokenDictionary
    Private Shared mInstance As TokenDictionary
    Public Shared ReadOnly Property Instance As TokenDictionary
        Get
            If mInstance Is Nothing Then
                mInstance = New TokenDictionary
            End If
            Return mInstance
        End Get
    End Property

    Private Sub New()
        Clear()
    End Sub

    Private mTokens As Dictionary(Of String, TokenDefinition)

    Private mCurrentToken As TokenDefinition
    Private mCurrentUsage As TokenUsage

    Public Sub Clear()
        mTokens = New Dictionary(Of String, TokenDefinition)
    End Sub

    Public Sub Load()
        Load(IO.Path.Combine("Data", "TokenDefinitions.xml"))
    End Sub
    Public Sub Load(DefinitionPath As String)
        Debug.WriteLine("Loading Token Definitions from '" & DefinitionPath & "'")
        Debug.Indent()
        Clear()

        Dim fileReader As IO.StreamReader = Nothing
        Try
            fileReader = New IO.StreamReader(DefinitionPath)
            Dim settings As New XmlReaderSettings
            settings.IgnoreComments = True
            settings.IgnoreWhitespace = True

            Dim reader As XmlReader = XmlReader.Create(fileReader, settings)

            Do While Not reader.EOF ' reader.Read
                If reader.IsStartElement("token") Then
                    Dim xml As String = reader.ReadOuterXml
                    Dim token As TokenDefinition = TokenDefinition.FromXmlString(xml)
                    'Debug.WriteLine(token.Name)
                    mTokens(token.Name) = token
                    reader.MoveToElement()
                Else
                    reader.Read()
                End If
            Loop
            fileReader.Close()
            mLoadingError = False
        Catch ex As Exception
            mLoadingError = True
            Trace.WriteLine("ERROR LOADING TOKEN DEFINITIONS:" & Environment.NewLine & ex.Message & Environment.NewLine & ex.StackTrace)
            Throw
        Finally
            If fileReader IsNot Nothing Then
                fileReader.Close()
                fileReader.Dispose()
            End If
        End Try
        Debug.Unindent()
        Debug.WriteLine("Token Definitions Loaded")
    End Sub

    Private Sub HandleDefinition(def As TokenDefinition)
        mTokens(def.Name) = def
    End Sub

    Private Shared Function ParseXmlEnum(Of t As Structure)(value As String) As t?
        Dim val As t
        If [Enum].TryParse(Of t)(value, val) Then
            Return val
        Else
            Return Nothing
        End If
    End Function

    Public Function GetUsage(tokenName As String, objectType As ObjectType, objectSubType As ObjectSubType) As TokenUsage
        If mTokens.ContainsKey(tokenName) Then
            Dim definition As TokenDefinition = mTokens(tokenName)
            Return definition.Usage(objectType, objectSubType)
        Else
            Return Nothing
        End If
    End Function

    Public Function GetUsage(tokenName As String, type As TypeCode) As TokenUsage
        Return GetUsage(tokenName, type.ObjectType, type.ObjectSubType)
    End Function

    Public Function GetDefinition(tokenName As String) As TokenDefinition
        If mTokens.ContainsKey(tokenName) Then
            Return mTokens(tokenName)
        Else
            Return Nothing
        End If
    End Function

    Public Function GetTokensFor(objectType As ObjectType, subType As ObjectSubType) As IEnumerable(Of String)
        Return (From token As TokenDefinition In mTokens.Values Where token.IsAllowedOn(objectType, subType) Select token.Name)
    End Function

    Private mLoadingError As Boolean = False
    Public ReadOnly Property LoadingError As Boolean
        Get
            Return mLoadingError
        End Get
    End Property

    Public Sub ReplaceToken(tokenName As String, tokenDefinition As TokenDefinition)
        mTokens(tokenName) = tokenDefinition
    End Sub

    Public Sub Save()
        Save(IO.Path.Combine("Data", "TokenDefinitions.xml"))
    End Sub

    Public Sub Save(path As String)
        Dim settings As New XmlWriterSettings
        settings.Indent = True
        settings.IndentChars = vbTab
        settings.NewLineChars = vbNewLine
        settings.NewLineHandling = NewLineHandling.Replace

        Dim xmlWriter As XmlWriter = Nothing
        Dim xml As New StringBuilder
        Try
            xmlWriter = xmlWriter.Create(xml, settings)
            xmlWriter.WriteStartDocument()
            xmlWriter.WriteStartElement("tokenDefinitions")
            For Each tokenName As String In mTokens.Keys.OrderBy(Function(x As String) x)
                Dim token As TokenDefinition = mTokens(tokenName)
                token.WriteXml(xmlWriter)
            Next
            xmlWriter.WriteEndElement()
        Catch ex As Exception
        End Try
        xmlWriter.Close()

        Dim s As IO.FileStream = Nothing
        Dim writer As IO.StreamWriter = Nothing
        Try
            s = New IO.FileStream(path, IO.FileMode.Create)
            writer = New IO.StreamWriter(s)
            writer.Write(xml.ToString)
            writer.Flush()
        Catch ex As Exception
            Throw
        Finally
            If writer IsNot Nothing Then
                writer.Close()
                writer.Dispose()
            End If
            If s IsNot Nothing Then
                s.Close()
                s.Dispose()
            End If
        End Try
    End Sub

End Class
